package com.datagateway.performance;

import com.datagateway.component.*;
import com.datagateway.model.ProcessedData;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

import static org.junit.jupiter.api.Assertions.*;

/**
 * 压力测试用例
 * 
 * @author Data Gateway Team
 * @version 1.0.0
 */
@ExtendWith(MockitoExtension.class)
class StressTestRunner {

    private DataBuffer dataBuffer;
    private GroovyScriptEngine scriptEngine;
    private DataValidationEngine validationEngine;
    private DataFormatConverter formatConverter;
    private RateLimiterManager rateLimiterManager;
    private CircuitBreakerManager circuitBreakerManager;

    @Mock
    private AlertManager alertManager;

    @BeforeEach
    void setUp() {
        dataBuffer = new DataBuffer();
        dataBuffer.setAlertManager(alertManager);
        dataBuffer.initialize();

        scriptEngine = new GroovyScriptEngine();
        scriptEngine.setAlertManager(alertManager);
        scriptEngine.initialize();

        validationEngine = new DataValidationEngine();
        validationEngine.setAlertManager(alertManager);
        validationEngine.initialize();

        formatConverter = new DataFormatConverter();
        formatConverter.setAlertManager(alertManager);
        formatConverter.initialize();

        rateLimiterManager = new RateLimiterManager();
        rateLimiterManager.setAlertManager(alertManager);
        rateLimiterManager.initialize();

        circuitBreakerManager = new CircuitBreakerManager();
        circuitBreakerManager.setAlertManager(alertManager);
        circuitBreakerManager.initialize();
    }

    @Test
    void testDataBufferStress() throws InterruptedException {
        int threadCount = 50;
        int operationsPerThread = 1000;
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        CountDownLatch latch = new CountDownLatch(threadCount);

        AtomicLong successCount = new AtomicLong(0);
        AtomicLong failureCount = new AtomicLong(0);
        long startTime = System.currentTimeMillis();

        // 并发添加数据
        for (int i = 0; i < threadCount; i++) {
            final int threadId = i;
            executor.submit(() -> {
                try {
                    for (int j = 0; j < operationsPerThread; j++) {
                        ProcessedData data = new ProcessedData();
                        data.setId("thread-" + threadId + "-data-" + j);
                        data.setContent("content-" + j);
                        data.setTimestamp(System.currentTimeMillis());

                        if (dataBuffer.addData(data)) {
                            successCount.incrementAndGet();
                        } else {
                            failureCount.incrementAndGet();
                        }
                    }
                } finally {
                    latch.countDown();
                }
            });
        }

        // 等待所有线程完成
        assertTrue(latch.await(60, TimeUnit.SECONDS));
        long endTime = System.currentTimeMillis();

        // 验证结果
        long totalOperations = threadCount * operationsPerThread;
        assertEquals(totalOperations, successCount.get() + failureCount.get());
        assertTrue(successCount.get() > 0);

        // 计算性能指标
        long processingTime = endTime - startTime;
        double throughput = (double) totalOperations / (processingTime / 1000.0);
        double successRate = (double) successCount.get() / totalOperations;

        System.out.println("数据缓冲压力测试结果:");
        System.out.println("总操作数: " + totalOperations);
        System.out.println("成功操作数: " + successCount.get());
        System.out.println("失败操作数: " + failureCount.get());
        System.out.println("处理时间: " + processingTime + "ms");
        System.out.println("吞吐量: " + String.format("%.2f", throughput) + " ops/sec");
        System.out.println("成功率: " + String.format("%.2f", successRate * 100) + "%");

        // 性能断言
        assertTrue(throughput > 1000, "吞吐量应该大于1000 ops/sec");
        assertTrue(successRate > 0.95, "成功率应该大于95%");

        executor.shutdown();
    }

    @Test
    void testGroovyScriptStress() throws InterruptedException {
        int threadCount = 20;
        int operationsPerThread = 500;
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        CountDownLatch latch = new CountDownLatch(threadCount);

        AtomicLong successCount = new AtomicLong(0);
        AtomicLong failureCount = new AtomicLong(0);
        long startTime = System.currentTimeMillis();

        // 准备脚本
        String script = """
            def transform(data) {
                data.content = data.content.toUpperCase()
                data.metadata['processed'] = true
                data.metadata['processTime'] = System.currentTimeMillis()
                return data
            }
            """;

        // 并发执行脚本
        for (int i = 0; i < threadCount; i++) {
            final int threadId = i;
            executor.submit(() -> {
                try {
                    for (int j = 0; j < operationsPerThread; j++) {
                        ProcessedData data = new ProcessedData();
                        data.setId("thread-" + threadId + "-data-" + j);
                        data.setContent("content-" + j);
                        data.setTimestamp(System.currentTimeMillis());

                        ProcessedData result = scriptEngine.executeScript(script, data);
                        if (result != null) {
                            successCount.incrementAndGet();
                        } else {
                            failureCount.incrementAndGet();
                        }
                    }
                } finally {
                    latch.countDown();
                }
            });
        }

        // 等待所有线程完成
        assertTrue(latch.await(60, TimeUnit.SECONDS));
        long endTime = System.currentTimeMillis();

        // 验证结果
        long totalOperations = threadCount * operationsPerThread;
        assertEquals(totalOperations, successCount.get() + failureCount.get());
        assertTrue(successCount.get() > 0);

        // 计算性能指标
        long processingTime = endTime - startTime;
        double throughput = (double) totalOperations / (processingTime / 1000.0);
        double successRate = (double) successCount.get() / totalOperations;

        System.out.println("Groovy脚本压力测试结果:");
        System.out.println("总操作数: " + totalOperations);
        System.out.println("成功操作数: " + successCount.get());
        System.out.println("失败操作数: " + failureCount.get());
        System.out.println("处理时间: " + processingTime + "ms");
        System.out.println("吞吐量: " + String.format("%.2f", throughput) + " ops/sec");
        System.out.println("成功率: " + String.format("%.2f", successRate * 100) + "%");

        // 性能断言
        assertTrue(throughput > 500, "吞吐量应该大于500 ops/sec");
        assertTrue(successRate > 0.95, "成功率应该大于95%");

        executor.shutdown();
    }

    @Test
    void testDataValidationStress() throws InterruptedException {
        int threadCount = 30;
        int operationsPerThread = 1000;
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        CountDownLatch latch = new CountDownLatch(threadCount);

        AtomicLong successCount = new AtomicLong(0);
        AtomicLong failureCount = new AtomicLong(0);
        long startTime = System.currentTimeMillis();

        // 准备测试数据
        String testData = """
            {
                "name": "测试用户",
                "email": "test@example.com",
                "phone": "13800138000",
                "age": 25
            }
            """;

        // 并发执行校验
        for (int i = 0; i < threadCount; i++) {
            executor.submit(() -> {
                try {
                    for (int j = 0; j < operationsPerThread; j++) {
                        DataValidationEngine.ValidationResult result = validationEngine.validate(testData, "user");
                        if (result.isValid()) {
                            successCount.incrementAndGet();
                        } else {
                            failureCount.incrementAndGet();
                        }
                    }
                } finally {
                    latch.countDown();
                }
            });
        }

        // 等待所有线程完成
        assertTrue(latch.await(60, TimeUnit.SECONDS));
        long endTime = System.currentTimeMillis();

        // 验证结果
        long totalOperations = threadCount * operationsPerThread;
        assertEquals(totalOperations, successCount.get() + failureCount.get());
        assertTrue(successCount.get() > 0);

        // 计算性能指标
        long processingTime = endTime - startTime;
        double throughput = (double) totalOperations / (processingTime / 1000.0);
        double successRate = (double) successCount.get() / totalOperations;

        System.out.println("数据校验压力测试结果:");
        System.out.println("总操作数: " + totalOperations);
        System.out.println("成功操作数: " + successCount.get());
        System.out.println("失败操作数: " + failureCount.get());
        System.out.println("处理时间: " + processingTime + "ms");
        System.out.println("吞吐量: " + String.format("%.2f", throughput) + " ops/sec");
        System.out.println("成功率: " + String.format("%.2f", successRate * 100) + "%");

        // 性能断言
        assertTrue(throughput > 2000, "吞吐量应该大于2000 ops/sec");
        assertTrue(successRate > 0.95, "成功率应该大于95%");

        executor.shutdown();
    }

    @Test
    void testDataFormatConversionStress() throws InterruptedException {
        int threadCount = 20;
        int operationsPerThread = 500;
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        CountDownLatch latch = new CountDownLatch(threadCount);

        AtomicLong successCount = new AtomicLong(0);
        AtomicLong failureCount = new AtomicLong(0);
        long startTime = System.currentTimeMillis();

        // 准备测试数据
        String jsonData = """
            {
                "name": "测试用户",
                "age": 25,
                "email": "test@example.com",
                "active": true
            }
            """;

        // 并发执行格式转换
        for (int i = 0; i < threadCount; i++) {
            executor.submit(() -> {
                try {
                    for (int j = 0; j < operationsPerThread; j++) {
                        DataFormatConverter.ConversionResult result = formatConverter.convert(jsonData, "JSON", "XML");
                        if (result.isSuccess()) {
                            successCount.incrementAndGet();
                        } else {
                            failureCount.incrementAndGet();
                        }
                    }
                } finally {
                    latch.countDown();
                }
            });
        }

        // 等待所有线程完成
        assertTrue(latch.await(60, TimeUnit.SECONDS));
        long endTime = System.currentTimeMillis();

        // 验证结果
        long totalOperations = threadCount * operationsPerThread;
        assertEquals(totalOperations, successCount.get() + failureCount.get());
        assertTrue(successCount.get() > 0);

        // 计算性能指标
        long processingTime = endTime - startTime;
        double throughput = (double) totalOperations / (processingTime / 1000.0);
        double successRate = (double) successCount.get() / totalOperations;

        System.out.println("数据格式转换压力测试结果:");
        System.out.println("总操作数: " + totalOperations);
        System.out.println("成功操作数: " + successCount.get());
        System.out.println("失败操作数: " + failureCount.get());
        System.out.println("处理时间: " + processingTime + "ms");
        System.out.println("吞吐量: " + String.format("%.2f", throughput) + " ops/sec");
        System.out.println("成功率: " + String.format("%.2f", successRate * 100) + "%");

        // 性能断言
        assertTrue(throughput > 1000, "吞吐量应该大于1000 ops/sec");
        assertTrue(successRate > 0.95, "成功率应该大于95%");

        executor.shutdown();
    }

    @Test
    void testRateLimiterStress() throws InterruptedException {
        int threadCount = 50;
        int requestsPerThread = 200;
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        CountDownLatch latch = new CountDownLatch(threadCount);

        AtomicLong allowedCount = new AtomicLong(0);
        AtomicLong rejectedCount = new AtomicLong(0);
        long startTime = System.currentTimeMillis();

        // 创建限流器
        rateLimiterManager.createRateLimiter("stress-limiter", "TOKEN_BUCKET", 1000, 500, 60, 1000);

        // 并发请求
        for (int i = 0; i < threadCount; i++) {
            executor.submit(() -> {
                try {
                    for (int j = 0; j < requestsPerThread; j++) {
                        if (rateLimiterManager.isAllowed("stress-limiter", 1)) {
                            allowedCount.incrementAndGet();
                        } else {
                            rejectedCount.incrementAndGet();
                        }
                    }
                } finally {
                    latch.countDown();
                }
            });
        }

        // 等待所有线程完成
        assertTrue(latch.await(60, TimeUnit.SECONDS));
        long endTime = System.currentTimeMillis();

        // 验证结果
        long totalRequests = threadCount * requestsPerThread;
        assertEquals(totalRequests, allowedCount.get() + rejectedCount.get());
        assertTrue(allowedCount.get() > 0);
        assertTrue(rejectedCount.get() > 0);

        // 计算性能指标
        long processingTime = endTime - startTime;
        double throughput = (double) totalRequests / (processingTime / 1000.0);
        double rejectionRate = (double) rejectedCount.get() / totalRequests;

        System.out.println("限流器压力测试结果:");
        System.out.println("总请求数: " + totalRequests);
        System.out.println("允许请求数: " + allowedCount.get());
        System.out.println("拒绝请求数: " + rejectedCount.get());
        System.out.println("处理时间: " + processingTime + "ms");
        System.out.println("吞吐量: " + String.format("%.2f", throughput) + " ops/sec");
        System.out.println("拒绝率: " + String.format("%.2f", rejectionRate * 100) + "%");

        // 性能断言
        assertTrue(throughput > 5000, "吞吐量应该大于5000 ops/sec");
        assertTrue(rejectionRate > 0, "应该有拒绝请求");

        executor.shutdown();
    }

    @Test
    void testCircuitBreakerStress() throws InterruptedException {
        int threadCount = 20;
        int operationsPerThread = 100;
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        CountDownLatch latch = new CountDownLatch(threadCount);

        AtomicLong successCount = new AtomicLong(0);
        AtomicLong failureCount = new AtomicLong(0);
        long startTime = System.currentTimeMillis();

        // 创建熔断器
        circuitBreakerManager.createCircuitBreaker("stress-breaker", 5, 3, 1000, 2000);

        // 并发执行
        for (int i = 0; i < threadCount; i++) {
            final int threadId = i;
            executor.submit(() -> {
                try {
                    for (int j = 0; j < operationsPerThread; j++) {
                        CircuitBreakerManager.CircuitBreakerResult<String> result = circuitBreakerManager.execute(
                            "stress-breaker", () -> {
                                if (j % 3 == 0) {
                                    throw new RuntimeException("Simulated failure");
                                }
                                return "success-" + threadId + "-" + j;
                            }
                        );
                        
                        if (result.isSuccess()) {
                            successCount.incrementAndGet();
                        } else {
                            failureCount.incrementAndGet();
                        }
                    }
                } finally {
                    latch.countDown();
                }
            });
        }

        // 等待所有线程完成
        assertTrue(latch.await(60, TimeUnit.SECONDS));
        long endTime = System.currentTimeMillis();

        // 验证结果
        long totalOperations = threadCount * operationsPerThread;
        assertEquals(totalOperations, successCount.get() + failureCount.get());
        assertTrue(successCount.get() > 0);

        // 计算性能指标
        long processingTime = endTime - startTime;
        double throughput = (double) totalOperations / (processingTime / 1000.0);
        double successRate = (double) successCount.get() / totalOperations;

        System.out.println("熔断器压力测试结果:");
        System.out.println("总操作数: " + totalOperations);
        System.out.println("成功操作数: " + successCount.get());
        System.out.println("失败操作数: " + failureCount.get());
        System.out.println("处理时间: " + processingTime + "ms");
        System.out.println("吞吐量: " + String.format("%.2f", throughput) + " ops/sec");
        System.out.println("成功率: " + String.format("%.2f", successRate * 100) + "%");

        // 性能断言
        assertTrue(throughput > 1000, "吞吐量应该大于1000 ops/sec");
        assertTrue(successRate > 0.5, "成功率应该大于50%");

        executor.shutdown();
    }

    @Test
    void testMemoryUsage() throws InterruptedException {
        int dataCount = 10000;
        long startMemory = getUsedMemory();
        long startTime = System.currentTimeMillis();

        // 添加大量数据
        for (int i = 0; i < dataCount; i++) {
            ProcessedData data = new ProcessedData();
            data.setId("memory-test-" + i);
            data.setContent("content-" + i + " ".repeat(100)); // 增加内容大小
            data.setTimestamp(System.currentTimeMillis());
            dataBuffer.addData(data);
        }

        long endMemory = getUsedMemory();
        long endTime = System.currentTimeMillis();

        // 计算内存使用
        long memoryUsed = endMemory - startMemory;
        long processingTime = endTime - startTime;

        System.out.println("内存使用测试结果:");
        System.out.println("数据数量: " + dataCount);
        System.out.println("内存使用: " + memoryUsed + " bytes");
        System.out.println("平均每条数据内存: " + (memoryUsed / dataCount) + " bytes");
        System.out.println("处理时间: " + processingTime + "ms");

        // 内存断言
        assertTrue(memoryUsed > 0, "应该使用内存");
        assertTrue(memoryUsed < 100 * 1024 * 1024, "内存使用应该小于100MB");

        // 清理内存
        dataBuffer.flushBuffer();
        System.gc();
    }

    private long getUsedMemory() {
        Runtime runtime = Runtime.getRuntime();
        return runtime.totalMemory() - runtime.freeMemory();
    }
}
